//
//  XRVideoTool.m
//  XR
//
//  Created by xiuren on 2017/3/21.
//  Copyright © 2017年 pepsikirk. All rights reserved.
//

#import "XSJVideoTool.h"
#import <AVFoundation/AVFoundation.h>
#import <assetslibrary/assetslibrary.h>
#import <CoreVideo/CVPixelBuffer.h>
#import <CoreMedia/CMSampleBuffer.h>


// 默认帧率
static NSUInteger const kKTMovieImagesTransferFPS = 10;

@implementation XRVideoInfoModel

@end

@implementation XSJVideoTool

- (void)transferMovie:(NSString *)movie {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL exist = [fileManager fileExistsAtPath:movie];
    NSError *error = nil;
    if (!exist) {
        NSString *errorString = [NSString stringWithFormat:@"文件不存在: %@", movie];
        error = [NSError errorWithDomain:@"KTMovieImagesTransferErrorDomain" code:-2000 userInfo:@{NSLocalizedDescriptionKey : errorString}];
        if (self.delegate && [self.delegate respondsToSelector:@selector(transferDidFinishedWithImages:error:)]) {
            [self.delegate transferDidFinishedWithImages:nil error:error];
        }
        return;
    }
    
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:movie] options:nil];
    AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    CMTime time = asset.duration;
    NSUInteger totalFrameCount = CMTimeGetSeconds(time) * kKTMovieImagesTransferFPS;
    NSMutableArray *timesArray = [NSMutableArray arrayWithCapacity:totalFrameCount];
    for (NSUInteger ii = 0; ii < totalFrameCount; ++ii) {
        CMTime timeFrame = CMTimeMake(ii, kKTMovieImagesTransferFPS);
        NSValue *timeValue = [NSValue valueWithCMTime:timeFrame];
        [timesArray addObject:timeValue];
    }
    generator.requestedTimeToleranceBefore = kCMTimeZero;
    generator.requestedTimeToleranceAfter = kCMTimeZero;
    __block NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:totalFrameCount];
    
    [generator generateCGImagesAsynchronouslyForTimes:timesArray completionHandler:^(CMTime requestedTime, CGImageRef  _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
        switch (result) {
            case AVAssetImageGeneratorFailed:
                [self sendToMainThreadError:error];
                break;
                
            case AVAssetImageGeneratorSucceeded: {
                UIImage *imageA = [UIImage imageWithCGImage:image];
                [imageArray addObject:imageA];
                NSUInteger index = requestedTime.value;
                if (index == totalFrameCount - 1) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if ([self.delegate respondsToSelector:@selector(transferDidFinishedWithImages:error:)]) {
                            [self.delegate transferDidFinishedWithImages:imageArray error:nil];
                        }
                    });
                }
            }
                break;
                
            default:
                break;
        }
    }];
}

- (void)sendToMainThreadError:(NSError *)error {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.delegate && [self.delegate respondsToSelector:@selector(transferDidFinishedWithImages:error:)]) {
            [self.delegate transferDidFinishedWithImages:nil error:error];
        }
    });
}

+ (void)removeMovieWithScope:(NSString *)scope {
    NSString *filePath = [[NSTemporaryDirectory() stringByAppendingPathComponent:@"Compressed"] stringByAppendingPathComponent:scope];
    NSFileManager *manager = [NSFileManager defaultManager];
    if ([manager fileExistsAtPath:filePath]) {
        NSError *error;
        [manager removeItemAtPath:filePath error:&error];
    }
}

/**
 *  将视频url转化为NSData数据,写入沙盒
 *
 *  @param 视频url   图片
 *  @param filePath   文件路径
 *
 *  @return
 */
+ (void)videoWithUrl:(NSURL *)url FilePath:(NSString *)filePath
{
    if ( !url || !filePath )
    {
        return;
    }
    
    ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
    [assetLibrary assetForURL:url resultBlock:^(ALAsset *asset)
     {
         ALAssetRepresentation *rep = [asset defaultRepresentation];
         char const *cvideoPath = [filePath UTF8String];
         FILE *file = fopen(cvideoPath, "a+");
         if (file)
         {
             const int bufferSize = 1024 * 1024;
             // 初始化一个1M的buffer
             Byte *buffer = (Byte*)malloc(bufferSize);
             NSUInteger read = 0, offset = 0, written = 0;
             NSError* err = nil;
             if (rep.size != 0)
             {
                 do
                 {
                     read = [rep getBytes:buffer fromOffset:offset length:bufferSize error:&err];
                     written = fwrite(buffer, sizeof(char), read, file);
                     offset += read;
                 }
                 while (read != 0 && !err);//没到结尾，没出错，ok继续
             }
             // 释放缓冲区，关闭文件
             free(buffer);
             buffer = NULL;
             fclose(file);
             file = NULL;
         }
     }
                 failureBlock:nil];
}


/**
 得到视频相关信息
 
 @param videoUrl 视频地址
 @return <#return value description#>
 */
+(XRVideoInfoModel*)getVideoInfo:(NSURL*)videoUrl
{
    if ( !videoUrl )
    {
        return nil;
    }
    
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
    if ( !asset )
    {
        return nil;
    }
    
    XRVideoInfoModel* info = [[XRVideoInfoModel alloc]init];
    
    //获取文件大小
    NSString* path = [videoUrl absoluteString];
    NSError* error = nil;
    info.fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error].fileSize;
    if (error)
    {
        path = [videoUrl path];
        info.fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error].fileSize;
    }
    
    //获取第一帧
    info.previewImage = [XSJVideoTool getVideoPreViewImage:videoUrl time:0];
    
    //获取时长
    CMTime time = [asset duration];
    info.duration = ceil(time.value/time.timescale);
    
    //属性数组
    NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
    
    if( [tracks count]>0 )
    {
        AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
        //宽高
        info.width = videoTrack.naturalSize.width;
        info.height = videoTrack.naturalSize.height;
        
        //旋转角度
        info.transform = videoTrack.preferredTransform;
        
        //fps
        info.fps = videoTrack.nominalFrameRate;
        
        //bps
        info.bps = videoTrack.estimatedDataRate;
        
        NSArray *formatDescriptions = [videoTrack formatDescriptions];
        if ( [formatDescriptions count]>0 )
        {
            
        }
    }
    
    return info;
}

//获取视频的大小
+ (NSUInteger)getVideoFileSize:(NSString *)videoUrlString
{
    NSUInteger fileSize = 0;
    NSURL *videoUrl = [NSURL fileURLWithPath:videoUrlString];
    
    //获取文件大小
    NSString* path = [videoUrl absoluteString];
    NSError* error = nil;
    fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error].fileSize;
    if (error)
    {
        path = [videoUrl path];
        fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error].fileSize;
    }
    
    return fileSize;
}


//获取视频的大小
+ (NSUInteger)getVideoFileSizebyAsset:(PHAsset *)asset
{
    PHAssetResource *resource = [[PHAssetResource assetResourcesForAsset:asset] firstObject];
    long long size = [[resource valueForKey:@"fileSize"] longLongValue];
    
    return size;
}


/**
 获取视频的任意一帧
 
 @param videoUrl 视频地址
 @param fTime 时间点
 @return 返回图片
 */
+ (UIImage *)getVideoPreViewImage:(NSURL *)videoUrl time:(NSInteger)ftime
{
    if ( !videoUrl || time<0 )
    {
        return nil;
    }
    
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
    
    AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    gen.appliesPreferredTrackTransform = YES;
    float second = ceilf(asset.duration.value / asset.duration.timescale);
    Float64 f = second / 6.0 * ftime;
    CMTime time = CMTimeMakeWithSeconds(f, 600);
    NSError *error = nil;
    CMTime actualTime;
    CGImageRef image = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
    UIImage *img = [[UIImage alloc] initWithCGImage:image];
    CGImageRelease(image);
    
    return img;
}

+ (void)getVideoPreViewImageWithAssset:(PHAsset *)asset time:(float)fTime complete:(void (^)(UIImage *))complete {
    PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
    options.version = PHImageRequestOptionsVersionCurrent;
    options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
    //允许从 iCloud 中获取图片和视频
    options.networkAccessAllowed = YES;
    PHImageManager *manager = [PHImageManager defaultManager];
    [manager requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
        AVURLAsset *urlAsset = (AVURLAsset *)asset;
        AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:urlAsset];
        gen.appliesPreferredTrackTransform = YES;
        CMTime time = CMTimeMakeWithSeconds(fTime, 600);
        NSError *error = nil;
        CMTime actualTime;
        CGImageRef image = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
        UIImage *img = [[UIImage alloc] initWithCGImage:image];
        CGImageRelease(image);
        
        if (complete) {
            complete(img);
        }
        //        NSURL *url = urlAsset.URL;
        //        NSData *data = [NSData dataWithContentsOfURL:url];
        
        //            NSLog(@"%@",data);
    }];
}

+ (void)compressWithAsset:(PHAsset *)asset success:(void (^)(NSString *, NSString *))success failure:(void (^)(NSString *))failure cancel:(void (^)())cancel {
    PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
    options.version = PHImageRequestOptionsVersionCurrent;
    options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
    //允许从 iCloud 中获取图片和视频
    options.networkAccessAllowed = YES;
    PHImageManager *manager = [PHImageManager defaultManager];
    [manager requestExportSessionForVideo:asset options:options exportPreset:AVAssetExportPresetMediumQuality resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
        
        NSString *resultDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"Compressed"];
        DLog(@"resultDir = %@", resultDir);
        NSFileManager *filemanager = [NSFileManager defaultManager];
        
        BOOL isExists = [filemanager fileExistsAtPath:resultDir];
        if (!isExists) {
            [filemanager createDirectoryAtPath:resultDir withIntermediateDirectories:YES attributes:nil error:nil];
        }
        
        // 用时间, 给文件重新命名, 防止视频存储覆盖
        NSDateFormatter *formater = [[NSDateFormatter alloc] init];
        [formater setDateFormat:@"yyyyMMddHHmmssSSS"];
        NSString *scope = [NSString stringWithFormat:@"ios%@.mp4", [formater stringFromDate:[NSDate date]]];
        NSString *resultPath = [resultDir stringByAppendingPathComponent:scope];
        
        exportSession.outputURL = [NSURL fileURLWithPath:resultPath];
        exportSession.shouldOptimizeForNetworkUse = YES;
        exportSession.outputFileType = AVFileTypeMPEG4;
        [exportSession exportAsynchronouslyWithCompletionHandler:^{
            switch ([exportSession status]) {
                case AVAssetExportSessionStatusFailed: {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (failure) {
                            NSError *error = [exportSession error];
                            DLog(@"%@",error);
                            failure([[exportSession error] localizedDescription]);
                        }
                    });
                    break;
                }
                    
                case AVAssetExportSessionStatusCancelled: {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (cancel) {
                            DLog(@"取消");
                            cancel();
                        }
                    });
                    break;
                }
                    
                case AVAssetExportSessionStatusUnknown: {
                    NSLog(@"Unknown");
                }
                    
                case AVAssetExportSessionStatusCompleted: {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (success) {
                            DLog(@"成功，路径：%@", resultPath);
                            success(resultPath, scope);
                        }
                    });
                    break;
                }
                    
                case AVAssetExportSessionStatusExporting: {
                    NSLog(@"Exporting");
                }
                    
                case AVAssetExportSessionStatusWaiting: {
                    NSLog(@"Waiting");
                }
                    
                default:
                    break;
            }
        }];
    }];
}

+ (UIImage *)getCoverImage:(NSURL *)outMovieURL atTime:(CGFloat)time isKeyImage:(BOOL)isKeyImage {
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:outMovieURL options:nil];
//    NSParameterAssert(asset);
    AVAssetImageGenerator *assetImageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    assetImageGenerator.appliesPreferredTrackTransform = YES;
    assetImageGenerator.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
    
    __block CGImageRef thumbnailImageRef = NULL;
    NSError *thumbnailImageGenerationError = nil;
    
    // 控制取图的时间点是否为关键帧，系统为了性能是默认取关键帧图片
    CMTime myTime = CMTimeMake(time, 1);
    if (!isKeyImage) {
        assetImageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
        assetImageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
//        CMTime duration = asset.duration;
        myTime = CMTimeMake(time*30,30);
    }
    
    thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:myTime actualTime:NULL error:nil];
    
    if (!thumbnailImageRef){
        DLog(@"thumbnailImageGenerationError: %@", thumbnailImageGenerationError);
    }
    
    UIImage *thumbnailImage = thumbnailImageRef ? [[UIImage alloc] initWithCGImage:thumbnailImageRef] : nil;
    
    CGImageRelease(thumbnailImageRef);
    
    return thumbnailImage;
}

+ (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr {
    NSURL *mediaUrl = [NSURL fileURLWithPath:mediaUrlStr];
    AVURLAsset *mediaAsset = [[AVURLAsset alloc] initWithURL:mediaUrl options:nil];
    CMTime duration = mediaAsset.duration;
    
    return duration.value / duration.timescale;
}

/**
 mov转mp4
 
 @param videoUrl <#videoUrl description#>
 @param completion <#completion description#>
 */
+(void)movTomp4:(NSURL*)videoUrl completion:(TransformOK)completion
{
    if ( !videoUrl )
    {
        return;
    }
    
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoUrl options:nil];
    
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:asset];
    
    NSLog(@"%@",compatiblePresets);
    
    if ([compatiblePresets containsObject:AVAssetExportPresetHighestQuality]) {
        
        AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality];
        
        NSString * resultDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"Transform"];
        NSLog(@"resultDir = %@",resultDir);
        NSFileManager *manager = [NSFileManager defaultManager];
        
        BOOL isExists = [manager fileExistsAtPath:resultDir];
        if (!isExists)
        {
            [manager createDirectoryAtPath:resultDir withIntermediateDirectories:YES attributes:nil error:nil];
        }
        
        // 用时间, 给文件重新命名, 防止视频存储覆盖
        NSDateFormatter *formater = [[NSDateFormatter alloc] init];
        [formater setDateFormat:@"yyyy-MM-dd-HH-mm-ss"];
        NSString* resultPath = [resultDir stringByAppendingPathComponent:[NSString stringWithFormat:@"output-%@.mp4", [formater stringFromDate:[NSDate date]]]];
        NSLog(@"resultPath = %@",resultPath);
        
        exportSession.outputURL = [NSURL fileURLWithPath:resultPath];
        exportSession.outputFileType = AVFileTypeMPEG4;
        exportSession.shouldOptimizeForNetworkUse = YES;
        
        [exportSession exportAsynchronouslyWithCompletionHandler:^(void)
         
         {
             NSError* error = nil;
             //状态判断
             if (exportSession.status==AVAssetExportSessionStatusUnknown)
             {
                 error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusUnknown"
                                                    code:-1001
                                                userInfo:nil];
             }
             else if (exportSession.status==AVAssetExportSessionStatusWaiting)
             {
                 error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusWaiting"
                                                    code:-1001
                                                userInfo:nil];
                 NSLog(@"AVAssetExportSessionStatusWaiting");
             }
             else if (exportSession.status==AVAssetExportSessionStatusExporting)
             {
                 error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusExporting"
                                                    code:-1001
                                                userInfo:nil];
                 NSLog(@"AVAssetExportSessionStatusExporting");
             }
             else if (exportSession.status==AVAssetExportSessionStatusCompleted)
             {
                 error = nil;
                 NSLog(@"AVAssetExportSessionStatusCompleted");
             }
             else if (exportSession.status==AVAssetExportSessionStatusFailed)
             {
                 error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusUnknown"
                                                    code:-1001
                                                userInfo:nil];
                 NSLog(@"AVAssetExportSessionStatusFailed");
             }
             
             //回调
             if (completion)
             {
                 completion(resultPath,error);
             }
             
         }];
        
    }
}


/**
 视频压缩
 
 @param videoUrl <#videoUrl description#>
 @param compressionType
 AVAssetExportPresetLowQuality
 AVAssetExportPresetMediumQuality
 VAssetExportPresetHighestQuality
 AVAssetExportPreset640x480
 AVAssetExportPreset1280x720
 @param completion <#completion description#>
 */
+(void)videoCompress:(NSURL*)videoUrl compressionType:(NSString *)compressionType completion:(TransformOK)completion
{
    if ( !videoUrl )
    {
        return;
    }
    
    AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:videoUrl options:nil];
    
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
    
    // 所支持的压缩格式中是否有 所选的压缩格式
    if ( ![compatiblePresets containsObject:compressionType] )
    {
        NSString* str = [NSString stringWithFormat:@"不支持 %@ 格式的压缩", compressionType];
        NSError* error = [[NSError alloc] initWithDomain:str
                                                    code:-1001
                                                userInfo:nil];
        //回调
        if (completion)
        {
            completion(nil,error);
        }
        return;
    }
    
    //压缩
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:compressionType];
    
    NSString * resultDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"Compressed"];
    NSLog(@"resultDir = %@",resultDir);
    NSFileManager *manager = [NSFileManager defaultManager];
    
    BOOL isExists = [manager fileExistsAtPath:resultDir];
    if (!isExists)
    {
        [manager createDirectoryAtPath:resultDir withIntermediateDirectories:YES attributes:nil error:nil];
    }
    
    // 用时间, 给文件重新命名, 防止视频存储覆盖
    NSDateFormatter *formater = [[NSDateFormatter alloc] init];
    [formater setDateFormat:@"yyyy-MM-dd-HH-mm-ss"];
    NSString* resultPath = [resultDir stringByAppendingPathComponent:[NSString stringWithFormat:@"output-%@.mp4", [formater stringFromDate:[NSDate date]]]];
    NSLog(@"resultPath = %@",resultPath);
    
    exportSession.outputURL = [NSURL fileURLWithPath:resultPath];
    exportSession.outputFileType = AVFileTypeMPEG4;
    exportSession.shouldOptimizeForNetworkUse = YES;
    
    [exportSession exportAsynchronouslyWithCompletionHandler:^(void)
     
     {
         NSError* error = nil;
         //状态判断
         if (exportSession.status==AVAssetExportSessionStatusUnknown)
         {
             error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusUnknown"
                                                code:-1001
                                            userInfo:nil];
         }
         else if (exportSession.status==AVAssetExportSessionStatusWaiting)
         {
             error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusWaiting"
                                                code:-1001
                                            userInfo:nil];
             NSLog(@"AVAssetExportSessionStatusWaiting");
         }
         else if (exportSession.status==AVAssetExportSessionStatusExporting)
         {
             error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusExporting"
                                                code:-1001
                                            userInfo:nil];
             NSLog(@"AVAssetExportSessionStatusExporting");
         }
         else if (exportSession.status==AVAssetExportSessionStatusCompleted)
         {
             error = nil;
             NSLog(@"AVAssetExportSessionStatusCompleted");
         }
         else if (exportSession.status==AVAssetExportSessionStatusFailed)
         {
             error = [[NSError alloc] initWithDomain:@"AVAssetExportSessionStatusUnknown"
                                                code:-1001
                                            userInfo:nil];
             NSLog(@"AVAssetExportSessionStatusFailed");
         }
         
         //回调
         if (completion)
         {
             completion(resultPath,error);
         }
         
     }];
}


/**
 保存图片到相册
 
 @param image <#image description#>
 @param delegate <#delegate description#>
 */
-(void)SaveImageToAlbum:(UIImage*)image withDelegate:(id <XSJVideoToolDelegate>)delegate
{
    self.delegate = delegate;
    
    if (image==nil)
    {
        if ([self.delegate respondsToSelector:@selector(SaveImageCompleted:)])
        {
            NSError *error = [[NSError alloc] initWithDomain:@"图片为空" code:-1 userInfo:nil];
            [self.delegate SaveImageCompleted:error];
        }
        return;
    }
    
    //保存图片到相册核心代码
    UIImageWriteToSavedPhotosAlbum(image, self, @selector(savedImageOK:didFinishSavingWithError:contextInfo:), nil);
}

//保存图片完成后调用的方法
-(void)savedImageOK:(UIImage*)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
    if ([self.delegate respondsToSelector:@selector(SaveImageCompleted:)])
    {
        [self.delegate SaveImageCompleted:error];
    }
}

/**
 保存视频到相册
 
 @param videoPath <#videoPath description#>
 @param delegate <#delegate description#>
 */
-(void)SaveVideoToAlbum:(NSString*)videoPath withDelegate:(id <XSJVideoToolDelegate>)delegate
{
    self.delegate = delegate;
    
    if (videoPath==nil)
    {
        if ([self.delegate respondsToSelector:@selector(SaveVideoCompleted:)])
        {
            NSError *error = [[NSError alloc] initWithDomain:@"视频地址为空" code:-2 userInfo:nil];
            [self.delegate SaveVideoCompleted:error];
        }
        return;
    }
    
    if ( NO==UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(videoPath) )
    {
        if ([self.delegate respondsToSelector:@selector(SaveVideoCompleted:)])
        {
            NSError *error = [[NSError alloc] initWithDomain:@"不允许保存，请检查本地路径" code:-3 userInfo:nil];
            [self.delegate SaveVideoCompleted:error];
        }
        return;
    }
    
    //保存视频到相册核心代码
    UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, @selector(savedVideoOK:didFinishSavingWithError:contextInfo:), nil);
}

//保存视频完成之后的回调
-(void)savedVideoOK:(UIImage*)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
    if ([self.delegate respondsToSelector:@selector(SaveVideoCompleted:)])
    {
        [self.delegate SaveVideoCompleted:error];
    }
}


/**
 将视频数据转为图片
 
 @param sampleBuffer
 @return
 */
+(UIImage*)CMSampleBufferRefToUIImage:(nonnull CMSampleBufferRef)sampleBuffer
{
    //制作 CVImageBufferRef
    CVImageBufferRef buffer;
    buffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    
    CVPixelBufferLockBaseAddress(buffer, 0);
    
    //从 CVImageBufferRef 取得影像的细部信息
    uint8_t *base;
    size_t width, height, bytesPerRow;
    base = CVPixelBufferGetBaseAddress(buffer);
    width = CVPixelBufferGetWidth(buffer);
    height = CVPixelBufferGetHeight(buffer);
    bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);
    
    //利用取得影像细部信息格式化 CGContextRef
    CGColorSpaceRef colorSpace;
    CGContextRef cgContext;
    colorSpace = CGColorSpaceCreateDeviceRGB();
    cgContext = CGBitmapContextCreate(base, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGColorSpaceRelease(colorSpace);
    
    //透过 CGImageRef 将 CGContextRef 转换成 UIImage
    CGImageRef cgImage;
    UIImage *image;
    cgImage = CGBitmapContextCreateImage(cgContext);
    image = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    CGContextRelease(cgContext);
    
    CVPixelBufferUnlockBaseAddress(buffer, 0);
    
    return image;
}


/**
 将图片转为视频数据源
 
 @param image
 @return
 */
+(CVPixelBufferRef _Nullable )UIImageToCVPixelBufferRef:(nonnull UIImage*)image
{
    CGSize size = image.size;
    CGImageRef imageRef = [image CGImage];
    
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
    CVPixelBufferRef pxbuffer = NULL;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer);
    
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
    
    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);
    
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst);
    NSParameterAssert(context);
    
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)), imageRef);
    
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);
    
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
    
    return pxbuffer;
}

@end
